package dockerdemo

import (
	"context"
	"dockertools/tools"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

var (
	imageList []string
	cli       *client.Client
	err       error
	isBool    string
)

// 用于 Docker 工具包创建的类
type DockerType struct {
	HostString string
}

func (d DockerType) InitClient() (*client.Client, error) {
	// 判断连接的 DockerDaemon 位于本机还是远程，如果是则进行远程连接
	if d.HostString != "" {
		cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation(),
			client.WithHost(fmt.Sprintf("%v%v", "tcp://", d.HostString)))
	} else {
		// 本地连接 Docker 进行管理
		cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
	}
	return cli, err
}

// 用于 Docker 镜像的导入
func LoadImage(cli *client.Client, loadDir string) {
	ctx := context.Background()

	f, err := os.Open(loadDir)
	defer f.Close()

	if err != nil {
		fmt.Println(err)
	}

	_, err = cli.ImageLoad(ctx, f, true)
	if err != nil {
		fmt.Println("镜像导入失败")
	}
}

func (d DockerType) LoadDirImage(cli *client.Client, dirString string) {
	if !tools.Exists(dirString) {
		fmt.Printf("指定的路径错误，请重新指定，路径不存在！ - %v \n", dirString)
		os.Exit(2)
	}

	if tools.IsDir(dirString) {
		files, err := ioutil.ReadDir(dirString)
		if err != nil {
			fmt.Println(err)
		}

		// 获取文件，并输出它们的名字
		for _, file := range files {
			LoadImage(cli, fmt.Sprintf("%v/%v", dirString, file.Name()))
			fmt.Printf("已导入镜像：%v！\n", fmt.Sprintf("%v/%v", dirString, file.Name()))
		}
	} else {
		LoadImage(cli, fmt.Sprintf("%v", dirString))
		fmt.Printf("已导入镜像：%v！\n", dirString)
	}

}

// 用于传递正则表达式匹配当前 Docker 镜像列表，并进行下载保存
func (d DockerType) SaveImageList(cli *client.Client, regularString, savepath string) {
	ctx := context.Background()

	// 确保目录存在
	tools.CreatePath(savepath)

	// 获取镜像列表
	images, err := cli.ImageList(ctx, types.ImageListOptions{})
	if err != nil {
		fmt.Println(err)
	}

	// 循环使用正则匹配镜像是否满足要求
	for _, image := range images {
		//打印当前开始匹配的镜像
		//fmt.Println(image.RepoTags[0])

		// 判断当前镜像是否满足正则
		if match, _ := regexp.MatchString(regularString, image.RepoTags[0]); match {
			imageList = append(imageList, image.RepoTags[0])
		}

	}

	// 答应满足正则的镜像列表
	fmt.Println(imageList)

	fmt.Println("输入匹配的镜像列表是否满足要求：（Y/N）")
	fmt.Scanln(&isBool)
	if isBool == "y" || isBool == "Y" {
		for _, saveImageName := range imageList {
			saveResponse, err := cli.ImageSave(context.Background(), []string{saveImageName})
			if err != nil {
				fmt.Println(err)
			}

			response, err := io.ReadAll(saveResponse)
			if err != nil {
				fmt.Println(err)
			}
			saveResponse.Close()

			saveImageTarName := strings.Replace(saveImageName, "/", "-", -1)
			saveImageTarName = strings.Replace(saveImageTarName, ":", "-", -1)
			saveImageTarName += ".tar"
			saveImageTarName = savepath + "/" + saveImageTarName
			tools.WFile(saveImageTarName, response, 0644)
		}
	} else {
		os.Exit(1)
	}
}
